import { _decorator, Camera, Color, Component, director, find, instantiate, Line, math, MeshRenderer, Node, Prefab, v2, v3, Vec2, Vec3, view } from 'cc';
const { ccclass, property } = _decorator;
import ResManager from './ResManager';

import { WorldCamera } from './WorldCamera';
import { WorldController } from './WorldController';
import { MapZone } from '../entity/MapZone';
import { PrefabEnum } from './PrefabEnum';
import { Plane } from '../world/Plane';




export default class WorldManager extends Component {
    private static _instance: WorldManager;

    static get instance(): WorldManager {
        if (this._instance == null) {
            this._instance = new WorldManager();
        }

        return this._instance
    }

    public zoneMapData: Map<string, MapZone> = new Map();
    /**当前地图的半径 */
    public step: number = 0
    /**每块地板的宽度 */
    public sizeX: number = v2(256, 128).length()
    /**每块地板的高度 */
    public sizeY: number = v2(256, 128).length()
    /**完整地图的半径 */
    public radius: number = 400
    /**地图中心X */
    public centerX: number = 0
    /**地图中心Y */
    public centerY: number = 0
    /**X轴方向 */
    public dirX: Vec3 = v3(256, -128, 0).normalize()
    /**Y轴方向 */
    public dirY: Vec3 = v3(256, 128, 0).normalize()

    public pickerPlane: Node;

    public async createFloor(posX: number = 0, posY: number = 0, stepX: number = 10, stepY: number = 10) {
        let plane = await ResManager.instance.loadAssetByUrl<Prefab>(PrefabEnum.Plane)

        // 正 正
        if (stepX > 0 && stepY > 0) {

            for (let x = posX; x < posX + stepX; x++) {
                for (let y = posY; y < posY + stepY; y++) {
                    this.createPlane(plane, x, y)
                }
            }
        }

        // 负 正
        if (stepX < 0 && stepY > 0) {

            for (let x = posX; x > posX + stepX; x--) {
                for (let y = posY; y < posY + stepY; y++) {
                    this.createPlane(plane, x, y)
                }
            }
        }

        // 负 负
        if (stepX < 0 && stepY < 0) {

            for (let x = posX; x > posX + stepX; x--) {
                for (let y = posY; y > posY + stepY; y--) {
                    this.createPlane(plane, x, y)
                }
            }
        }

        // 正 负
        if (stepX > 0 && stepY < 0) {

            for (let x = posX; x < posX + stepX; x++) {
                for (let y = posY; y > posY + stepY; y--) {
                    this.createPlane(plane, x, y)
                }
            }
        }




    }

    createPlane(plane, x, y) {
        let p = this.xyToShow(x, y)
        for (let ch of WorldController.instance.stage.children) {
            if (ch.name == p.x + ':' + p.y) {
                return
            }
        }

        let node = instantiate(plane);
        let temp = v3(0, 0, 0)

        temp.add(this.dirX.clone().multiplyScalar(x * this.sizeX))
        temp.add(this.dirY.clone().multiplyScalar(y * this.sizeY))
        node.position = temp
        // node.position = v3(x * size, y * size, 0)
        node.parent = WorldController.instance.stage;
        node.getComponent(Plane).setRealPosition(x, y)

        
    }

    // 地图格子的真实坐标，转换成显示坐标
    xyToShow(x: number, y: number) {
        let radius = WorldManager.instance.radius
        let len = radius * 2 + 1


        let dataX = x % len
        let dataY = y % len

        if (dataX > 0) {
            if (dataX > radius) {
                dataX = -radius + (dataX - radius) - 1
            }
        } else {
            if (dataX < -radius) {
                dataX = radius - (-radius - dataX) + 1
            }
        }

        if (dataY > 0) {
            if (dataY > radius) {
                dataY = -radius + (dataY - radius) - 1
            }
        } else {
            if (dataY < -radius) {
                dataY = radius - (-radius - dataY) + 1
            }
        }

        return { x: dataX, y: dataY }
    }

    public async initWorld(x: number = 0, y: number = 0, step: number = 10) {


        this.centerX = x;
        this.centerY = y;
        this.step = step



        //创建原点
        this.createFloor(x, y, 1, 1)


        //创建上下左右
        await this.createFloor(x, y + 1, 1, step)
        await this.createFloor(x, y - 1, 1, -step)
        await this.createFloor(x + 1, y, step, 1)
        await this.createFloor(x - 1, y, -step, 1)
        //创建东北方
        await this.createFloor(x + 1, y + 1, step, step)
        //创建西北方
        await this.createFloor(x - 1, y + 1, -step, step)
        //创建西南方
        await this.createFloor(x - 1, y - 1, -step, -step)
        // 创建东南方
        await this.createFloor(x + 1, y - 1, step, -step)

        // 删除外围的地板
        this.removeOuterPlane()

    }

    removeOuterPlane() {


        //根据相机的坐标和地图格子Plane的坐标，计算出Plane是否在视野之外，并删除视野之外的地图格子

        let cameraPos = WorldCamera.instance.center


        let children = WorldController.instance.stage.children

        console.log('removeOuterPlane:' + children.length)

        for (let i = children.length - 1; i >= 0; i--) {
            let node = children[i]
            let pos = node.getPosition()

            let offset = pos.clone().subtract(cameraPos)
            let newoffset = this.convertCoord(offset)
            let x = newoffset.x
            let y = newoffset.y

            if (Math.abs(x / this.sizeX) > this.step || Math.abs(y / this.sizeY) > this.step) {
                node.removeFromParent()
                node.destroy()
            }
        }

        console.log('removeOuterPlane:' + WorldController.instance.stage.children.length)
        // 计算出重复的地图格子，调式的时候用
        // let map = {}
        // for(let item of WorldController.instance.stage.children){
        //     let name = item.name
        //     if(map[name]){
        //         console.log(name)
        //         continue
        //     }
        //     map[name] = name
        // }


    }
    // 根据数据创建局部地图
    public async createPartMap(data: MapZone[][], setCameraPos: boolean = true) {

        // zoneId转换成 x, y，并保存地图数据到 this.zoneMapData，后面会用到
        this.zoneMapData.clear()
        for (let list of data) {
            for (let item of list) {
                let a = MapZone.getXyByZoneId(item.zoneId, this.radius)
                item.x = a[0]
                item.y = a[1]
                this.zoneMapData.set(item.x + ':' + item.y, MapZone.createByObj(item))
            }
        }
        // 判断是否要设置相机的位置
        if (setCameraPos) {

            // 计算出地图的中心点X,Y
            let centerIndex = (data.length - 1) / 2
            this.centerX = data[centerIndex][centerIndex].x
            this.centerY = data[centerIndex][centerIndex].y
            //根据地图中心点，设置相机的位置，
            let temp = v3(0, 0, 0)
            temp.add(this.dirX.clone().multiplyScalar(this.centerX * this.sizeX))
            temp.add(this.dirY.clone().multiplyScalar(this.centerY * this.sizeY))
            WorldCamera.instance.node.position = temp
            //  WorldCamera.instance.node.position = v3(this.centerX * this.size, this.centerY * this.size, pos.z)

        } else {
            let pos = WorldCamera.instance.node.position
            let newPos = this.convertCoord(pos)
            let x = newPos.x
            let y = newPos.y

            this.centerX = Math.floor(x / this.sizeX)
            this.centerY = Math.floor(y / this.sizeY)
        }
        // 相机的取整位置center
        let v = v3(0, 0, 0)
        v.add(this.dirX.clone().multiplyScalar(this.centerX * this.sizeX))
        v.add(this.dirY.clone().multiplyScalar(this.centerY * this.sizeY))
        WorldCamera.instance.center = v
        // WorldCamera.instance.center = v3(this.centerX * this.sizeX, this.centerY * this.sizeY, 0)



        //根据地图中心点和地图半径，创建出当前地图
        await WorldManager.instance.initWorld(this.centerX, this.centerY, (data.length - 1) / 2);

        //给地图上的格子Plane，加上数据zoneData
        let children = WorldController.instance.stage.children
        for (let ch of children) {
            if (this.zoneMapData.has(ch.name)) {
                ch.getComponent(Plane).setZone(this.zoneMapData.get(ch.name))
            }

        }


    }

    /**
     * 将正常的直角坐标系，转换成自定义的世界地图坐标系
     * @param a 
     * @returns 
     */
    public convertCoord(a: Vec3): Vec3 {

        let angleList = []
        let hu = Math.atan2(this.dirX.y, this.dirX.x)
        let angle = hu * 180 / Math.PI
        angleList.push(angle)

        hu = Math.atan2(this.dirY.y, this.dirY.x)
        angle = hu * 180 / Math.PI
        angleList.push(angle)

        let ax = v3(0, 0, 0).subtract(this.dirX)
        hu = Math.atan2(ax.y, ax.x)
        angle = hu * 180 / Math.PI
        angleList.push(angle)

        let ay = v3(0, 0, 0).subtract(this.dirY)
        hu = Math.atan2(ay.y, ay.x)
        angle = hu * 180 / Math.PI
        angleList.push(angle)

        
        let area = 1
        hu = Math.atan2(a.y, a.x)
        angle = hu * 180 / Math.PI
        if (angle >= angleList[0] && angle <= angleList[1]) {
            area = 1
        }
        if (angle > angleList[1] && angle <= angleList[2]) {
            area = 2
        }

        if (angle > angleList[2] || angle <= angleList[3]) {
            area = 3
        }
        if (angle < angleList[0] && angle > angleList[3]) {
            area = 4
        }

        
        if (area == 1) {
            let ra = Vec3.angle(a, this.dirX)
            let len = Math.cos(ra) * a.length()
            let sLen = Math.sin(ra) * a.length()
            let dirAngle = Vec3.angle(this.dirX, this.dirY)
            let y = sLen / Math.sin(dirAngle)
            let x = Math.cos(dirAngle) * y
            x = len - x
            return v3(x, y, 0)
        }

        if(area == 2){
            let dirX = v3(0, 0, 0).subtract(this.dirX)
            let ra = Vec3.angle(a,  dirX)
            let len = Math.cos(ra) * a.length()
            let sLen = Math.sin(ra) * a.length()
            let dirAngle = Vec3.angle(dirX, this.dirY)
            let y = sLen / Math.sin(dirAngle)
            let x = Math.cos(dirAngle) * y
            x = len - x
          
            return v3(-x, y, 0)
        }

        if(area == 3){
            let dirX = v3(0, 0, 0).subtract(this.dirX)
            let dirY = v3(0, 0, 0).subtract(this.dirY)
            let ra = Vec3.angle(a,  dirX)
            let len = Math.cos(ra) * a.length()
            let sLen = Math.sin(ra) * a.length()
            let dirAngle = Vec3.angle(dirX, dirY)
            let y = sLen / Math.sin(dirAngle)
            let x = Math.cos(dirAngle) * y
            x = len - x
            return v3(-x, -y, 0)
        }

        if(area == 4){
            let dirX = this.dirX
            let dirY = v3(0, 0, 0).subtract(this.dirY)
            let ra = Vec3.angle(a,  dirX)
            let len = Math.cos(ra) * a.length()
            let sLen = Math.sin(ra) * a.length()
            let dirAngle = Vec3.angle(dirX, dirY)
            let y = sLen / Math.sin(dirAngle)
            let x = Math.cos(dirAngle) * y
            x = len - x
            return v3(x, -y, 0)
        }

    }

    /**
     * 根据地图格子的 x y ，算出世界坐标
     * @param coord x, y
     * @returns 
     */
    getWorldPostionByXY(coord:Vec2):Vec3{
        let x = this.dirX.clone().multiplyScalar(coord.x * this.sizeX)
        let y = this.dirY.clone().multiplyScalar(coord.y * this.sizeY)
        let pos = x.clone().add(y)
        let stagePos = find('Canvas/Stage').worldPosition
        pos.add(stagePos)
        return pos
    }

}


